package com.sdsmdg.harjot.materialshadows.utilities;

import java.util.Comparator;

public class Point2D implements Comparable<Point2D> {
    /**
     * 初始化一个比较器
     */
    public final Comparator<Point2D> POLAR_ORDER = new PolarOrder();
    /**
     * x1坐标
     */
    private final double x1; // x1 coordinate
    private final double y1; // y1 coordinate
    private static int NUMBER = -1;

    /**
     * 初始化坐标系
     *
     * @param x1 坐标系
     * @param y1 坐标系
     */
    public Point2D(double x1, double y1) {
        if (Double.isInfinite(x1) || Double.isInfinite(y1)) {
            throw new IllegalArgumentException("Coordinates must be finite");
        }
        if (Double.isNaN(x1) || Double.isNaN(y1)) {
            throw new IllegalArgumentException("Coordinates cannot be NaN");
        }
        if (x1 == 0.0) {
            x1 = 0.0; // convert -0.0 to +0.0
        }
        if (y1 == 0.0) {
            y1 = 0.0; // convert -0.0 to +0.0
        }
        this.x1 = x1;
        this.y1 = y1;
    }

    /**
     * 返回x1坐标
     *
     * @return x1
     */
    public double x() {
        return x1;
    }

    /**
     * 返回y1坐标
     *
     * @return y1
     */
    public double y() {
        return y1;
    }

    /**
     * 返回r
     *
     * @return r
     */
    public double r() {
        return Math.sqrt(x1 * x1 + y1 * y1);
    }

    /**
     * 逆时针
     *
     * @param a1 Point2D
     * @param b1 Point2D
     * @param c1 Point2D
     * @return ccw
     */
    public static int ccw(Point2D a1, Point2D b1, Point2D c1) {
        double area2 = (b1.x1 - a1.x1) * (c1.y1 - a1.y1) - (b1.y1 - a1.y1) * (c1.x1 - a1.x1);
        if (area2 < 0) {
            return NUMBER;
        }
        else if (area2 > 0) {
            return +1;
        }
        else {
            return 0;
        }
    }

    /**
     * 相比于
     *
     * @param that Point2D
     * @return compareTo
     */
    public int compareTo(Point2D that) {
        if (this.y1 < that.y1) {
            return NUMBER;
        }
        if (this.y1 > that.y1) {
            return +1;
        }
        if (this.x1 < that.x1) {
            return NUMBER;
        }
        if (this.x1 > that.x1) {
            return +1;
        }
        return 0;
    }

    /**
     * 比较器 秩序
     *
     * @since 2021-06-01
     */
    private class PolarOrder implements Comparator<Point2D> {
        public int compare(Point2D q1, Point2D q2) {
            double dx11 = q1.x1 - x1;
            double dy11 = q1.y1 - y1;
            double dx12 = q2.x1 - x1;
            double dy12 = q2.y1 - y1;

            if (dy11 >= 0 && dy12 < 0) {
                return NUMBER; // q1 above; q2 below
            }
            else if (dy12 >= 0 && dy11 < 0) {
                return +1; // q1 below; q2 above
            }
            else if (dy11 == 0 && dy12 == 0) { // 3-collinear and horizontal
                if (dx11 >= 0 && dx12 < 0) {
                    return NUMBER;
                }
                else if (dx12 >= 0 && dx11 < 0) {
                    return +1;
                }
                else {
                    return 0;
                }
            } else {
                return -ccw(Point2D.this, q1, q2); // both above or below
            }
        }
    }

    /**
     * 比较
     *
     * @param other Object
     * @return equals
     */
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        }
        if (other == null) {
            return false;
        }
        if (other.getClass() != this.getClass()) {
            return false;
        }
        Point2D that = (Point2D) other;
        return this.x1 == that.x1 && this.y1 == that.y1;
    }

    /**
     * 字符串
     *
     * @return toString
     */
    public String toString() {
        return "(" + x1 + ", " + y1 + ")";
    }

    /**
     * hashCode
     *
     * @return hashCode
     */
    public int hashCode() {
        int hashx1 = ((Double) x1).hashCode();
        int hashy1 = ((Double) y1).hashCode();
        return 31 * hashx1 + hashy1;
    }
}